using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;

namespace minega
{
	/// <summary>
	/// Class holding the different states of the cells.
	/// </summary>
	public class CellStates
	{
		/// <summary>
		/// Byte-array containing the state of the cells.
		/// Cells with an odd index are in the high part and the even indiced cells are in the low part of the byte.
		/// </summary>
		private byte[] _raw;
		/// <summary>
		/// Width and height of the grid.
		/// </summary>
		private int _width, _height;

		/// <summary>
		/// Gets the width of the grid.
		/// </summary>
		public int Width
		{
			get { return _width; }
		}
		/// <summary>
		/// Gets the height of the grid.
		/// </summary>
		public int Height
		{
			get { return _height; }
		}

		/// <summary>
		/// Gets or sets the CellStateFlag of the cell at (x, y).
		/// </summary>
		/// <param name="x">x-coordinate of the cell.</param>
		/// <param name="y">y-coordinate of the cell.</param>
		/// <returns>The current CellStateFlag of the cell.</returns>
		public byte this[int x, int y]
		{
			get 
            {
                if (x >= _width)
                    throw new IndexOutOfRangeException();

                int idx = x + y * _width;
                int rawIdx = idx / 2;
                return (byte)((idx % 2 == 0) ? _raw[rawIdx] & 0x0F : _raw[rawIdx] >> 4);
            }
			set
			{
                if (x >= _width)
                    throw new IndexOutOfRangeException();

                int idx = x + y * _width;
                int rawIdx = idx / 2;
                _raw[rawIdx] = (byte)((idx % 2 == 0) 
                    ? (_raw[rawIdx] & 0xF0) + (value & 0x0F) 
                    : (_raw[rawIdx] & 0x0F) + (value << 4));
			}
		}

		/// <summary>
		/// Initializes the members to zero.
		/// </summary>
		public CellStates()
            : this(0, 0)
		{

		}

		/// <summary>
		/// Sets the width and height of the new object.
		/// </summary>
		/// <param name="w">Width of the grid.</param>
		/// <param name="h">Height of the grid.</param>
		public CellStates(int w, int h)
		{
			_width = w;
			_height = h;
			// 2 cells / byte
			_raw = new byte[(_width * _height + 1) / 2];
		}

		/// <summary>
		/// Sets all cell states to CellStateFlags.Normal
		/// </summary>
		public void Normal()
		{
			int count = (_width * _height + 1) / 2;
			byte val = (byte)((CellStateFlags.Normal << 4) + CellStateFlags.Normal);
			for (int i = 0; i < count; i++)
			{
				_raw[i] = val;
			}
		}

		public byte NeighbouringFlags(int cellX, int cellY)
		{
			byte flags = 0;
			Rectangle rect = new Rectangle(0, 0, _width, _height);
			for (byte b = Neighbour.UL; b <= Neighbour.DR; b++)
			{
				Point pt = NeighbourPos.GetNeighbour(b, cellX, cellY);
				if (rect.Contains(pt))
				{
					if (this[pt.X, pt.Y] == CellStateFlags.Flag)
						flags++;
				}
			}
			return flags;
		}
	}
}